﻿#ifndef WNODEMANAGER_H
#define WNODEMANAGER_H

#include <wx/thread.h>
#include <mutex>          // 必须包含
#include <shared_mutex>   // 必须包含（C++17）
#include <unordered_map>

#include "../singleton.h"
#include "../network/networkframemanager.h"
#include "crouteconditions.h"
#include "wbasenode.h"
#include "wmountnode.h"
#include "wsignallampnode.h"
#include "wswitchnode.h"
#include "../signal.hpp"

extern "C" {
#include "../cjson.h"
}

class WNodeManager;

/// 区段的结点类型
class tagSectNode : public NedAllocatedObject
{
public:
    tagSectNode()
        : operstate(NodeOperState::NORMAL),
          deviceID(-1),
          clearsignalcount(0),
          curSwitchState(SwitchState::POSITIVE),
          signalstate(NodeSignalState::NOSIGNAL),
          lastsignalstate(NodeSignalState::NOSIGNAL),
          accessrule(SectAccessRule::ACCESS_NULL) {}
    tagSectNode(wxString sname,NodeOperState nos,NodeSignalState nss,int deviceid)
        : sectname(sname),operstate(nos),signalstate(nss),
          lastsignalstate(NodeSignalState::NOSIGNAL),
          deviceID(deviceid),
          curSwitchState(SwitchState::POSITIVE),
          clearsignalcount(0),
          accessrule(SectAccessRule::ACCESS_NULL) {}

    // 检测进路是否在区段中
    int isInSect(std::vector<tagSLRouteNode*> decnodes,int *startPosition);
    wxColour getStateColor(void);
    inline void setAccessRule(int rule) { accessrule = (SectAccessRule)rule; }
    inline int getAccessRule(void) const { return (SectAccessRule)accessrule; }
    inline void setSectOperState(int state) { operstate = (NodeOperState)state; }
    inline int getSectOperState(void) const { return operstate; }
    inline void setSignalState(int state) { signalstate = (NodeSignalState)state; }
    inline int getSignalState(void) const { return signalstate; }
    inline void setLastSignalState(int state) { lastsignalstate = (NodeSignalState)state; }
    inline int getLastSignalState(void) const { return lastsignalstate; }
    inline void setCurrentSwitchState(int state) { curSwitchState = (SwitchState)state; }
    inline int getCurrentSwitchState(void) const { return (int)curSwitchState; }
    inline bool isInLastSects(wxString sect)
    {
        for(int i=0;i<lastsects.size();i++)
            if(lastsects[i] == sect)
                return true;

        return false;
    }
    inline bool isInNextSects(wxString sect)
    {
        for(int i=0;i<nextsects.size();i++)
            if(nextsects[i] == sect)
                return true;

        return false;
    }
    inline wxVector<WBaseNode*> getSectNodes(int org)
    {
        std::map<int,wxVector<WBaseNode*>>::iterator iter = nodes.find(org);
        if(iter == nodes.end())
            return wxVector<WBaseNode*>();

        return (*iter).second;
    }
    void clearLock();
    inline wxVector<wxString> getLastSects(void)
    {
        wxVector<wxString> decSects;
        for(int i=0;i<lastsects.size();i++)
            decSects.push_back(lastsects[i]);
        return decSects;
    }
    inline wxString getLastSect(int index)
    {
        if(index < 0 || index >= lastsects.size())
            return "";

        return lastsects[index];
    }
    inline wxVector<wxString> getNextSects(void)
    {
        wxVector<wxString> decSects;
        for(int i=0;i<nextsects.size();i++)
            decSects.push_back(nextsects[i]);
        return decSects;
    }
    inline wxString getNextSect(int index)
    {
        if(index < 0 || index >= nextsects.size())
            return "";

        return nextsects[index];
    }
    inline bool isExistBaseNode(WBaseNode* pbasenode)
    {
        if(nodes.empty() || pbasenode == NULL)
            return false;

        std::map<int,wxVector<WBaseNode*>>::iterator iter = nodes.begin();
        for(;iter != nodes.end();++iter)
        {
            wxVector<WBaseNode*>::iterator iternode = std::find((*iter).second.begin(),
                                                                 (*iter).second.end(),
                                                                 pbasenode);
            if(iternode != (*iter).second.end())
                return true;
        }

        return false;
    }

    wxString sectname;
    int deviceID;
    NodeOperState operstate;
    NodeSignalState signalstate,lastsignalstate;
    SectAccessRule accessrule;
    int clearsignalcount;
    SwitchState curSwitchState;
    std::map<int,wxVector<WBaseNode*>> nodes;
    wxArrayString lastsects,nextsects;
};

struct tagRoute : public NedAllocatedObject
{
    inline wxVector<wxString> getAllSects(void)
    {
        wxVector<wxString> decSects;

        std::unordered_map<wxString,wxVector<tagSLRouteNode>>::iterator iter = sectNodes.begin();
        for(;iter != sectNodes.end();++iter)
            decSects.push_back((*iter).first);

        return decSects;
    }

    inline wxVector<tagSLRouteNode> getSectNodes(wxString sectName)
    {
        std::unordered_map<wxString,wxVector<tagSLRouteNode>>::iterator iter = sectNodes.find(sectName);
        if(iter != sectNodes.end())
            return (*iter).second;

        return wxVector<tagSLRouteNode>();
    }

    wxString closeAllLights(wxString sectName);

    void clearAllSect(void);

    wxString startLight,endLight;
    std::unordered_map<wxString,wxVector<tagSLRouteNode>> sectNodes;
};

class WNodeManager : public sigslot::has_slots<>,
                     public NetworkFrameManager,
                     public Singleton<WNodeManager>
{
public:
    WNodeManager();
    ~WNodeManager();

    /// 导入json配置
    bool loadJsonConfig(const char* configstr);
    /// 保存json配置
    bool saveJsonConfig(wxString configfilepath="");

    /// 设置工作范围
    inline void setWorkingRect(const wxRect& rect) { mWorkingRect = rect; }
    /// 得到工作范围
    inline const wxRect& getWorkingRect(void) { return mWorkingRect; }

    /// 添加一个挂接点
    WMountNode* addMountNode(wxString nodeName,wxRealPoint pos);
    /// 添加一个信号灯
    WSignalLampNode* addSignalLamp(wxString nodeName,wxRealPoint pos);
    /// 添加一个道岔
    WSwitchNode* addSwitch(wxString nodeName,wxRealPoint pos);

    /// 清除所有的数据
    void clear(void);
    /// 删除所有的结点
    void deleteAllNodes(void);
    /// 设置结点的工作模式
    void setWorkingMode(WorkingMode mode);
    /// 删除指定名称的结点
    bool deleteNodeByName(wxString nodeName);
    /// 得到指定名称的结点
    WBaseNode* getNodeByName(wxString nodeName);
    /// 得到指定坐标的结点
    WBaseNode* getNodeByPoint(wxPoint point);
    /// 得到指定设备ID的结点
    WBaseNode* getNodeByDeviceID(int deviceid);
    /// 设置鼠标光标
    void setMouseCursor(int cursorid);
    /// 控制信号灯
    bool controlTheSignalLamp(wxString nodeName,bool isOpen,luabridge::LuaRef pcallback);
    /// 得到所有的结点
    inline std::map<wxString,WBaseNode*> getAllNodes(void) { return mNodes; }
    /// 打印进路条件
    void printSect(const tagRouteCondiItem* routecondiitem);
    /// 检测两个结点之间进路的有效性
    wxVector<tagRouteCondiItem*> checkRoute(wxString startNode,wxString endNode);
    /// 得到两个结点之间的进路
    wxVector<tagSLRouteNode> getRoute(wxString startNode,wxString endNode,bool isaddother=false);
    /// 添加一条进路到系统中
    wxVector<tagRoute*> addRoute(wxVector<tagSLRouteNode> resultRouteNodes);
    /// 取消开始信号灯的指定进路
    bool cancelRoute(wxString startNode,luabridge::LuaRef pcallback);
    /// 删除开始信号灯的指定进路
    bool deleteRoute(wxString startNode);
    /// 得到指定的进路
    tagRoute* getSelectedRoute(wxString startLight,wxString endLight);
    /// 关闭进路中指定区段的信号灯
    wxString closeRouteAllLights(wxString sectName);
    /// 得到所有的进行中的进路
    wxVector<tagRoute*> getAllRoutes(void);
    /// 自动清除进行中的进路
    void autoDeleteSelectedRoute(void);
    /// 添加新的区段
    bool addSect(tagSectNode *newsect);
    /// 得到指定名称的区段
    tagSectNode* getSect(wxString sectName);
    /// 根据指定结点得到结点所在区段
    tagSectNode* getSectByNode(WBaseNode* node);
    /// 得到指定设备ID的区段
    tagSectNode* getSectByDeviceID(int deviceid);
    /// 根据设备ID得到区段名称
    wxString getSectNameByDeviceID(int deviceid);
    /// 删除指定名称的区段
    bool deleteSectByName(wxString sectName);
    /// 更改区段的名称
    bool updateSectByName(wxString oldsectName,wxString newsectName);
    /// 得到所有的区段
    inline std::map<wxString,tagSectNode*> getAllSects(void) { return mSects; }
    /// 设置指定区段的操作状态
    void setSectOperState(wxString sectName,int state);
    /// 设置指定区段的信号状态
    void setSectSignalState(tagSectNode *pSectNode,int state);
    /// 发送信号到设备
    bool sendSignal(std::string opertype,std::string signalMsg,int interval,luabridge::LuaRef pcallback);
    /// 计算站场指定结点挂载点的角度
    void computerNodeMountAngles(WBaseNode* basenode);
    /// 删除与关联结点有关的挂载点
    bool deleteMountPointByNode(WBaseNode* node);
    inline std::mutex* getSectMutex(void) { return &m_SectMutex; }
    /// 屏幕是否被锁住
    inline bool isLockedScreen(void) { return mLockedScreen; }

    /// 开始定时器
    void startTimer(const char* name,int interval,int runCount,luabridge::LuaRef pcallback);
    /// 停止指定定时器
    void stopTimer(const char* name,bool state);
    /// 停止所有定时器
    void stopAllTimer(void);
    /// 处理所有定时器事件
    void onProcessAllTimerEvent(void);

    /// 工作区域改变
    void changeWorkingRect(wxRect workingrect);
    /// 更新
    void update(void) {}
    /// 绘制
    void draw(maindrawscene *painter);
    /// 重置所有结点状态
    void resetAllNodes(void);
    /// 处理鼠标事件
    WBaseNode* OnMMouseEvent(wxMouseEvent event);
    /// 处理道岔状态变化导致区段变化事件
    void slot_processSwitchChangeToSect(wxString switchName="");

    /// 处理网络二进制消息
    virtual void OnProcessNetData(WTcpClient* client,int msgType,wxMemoryBuffer& data);

private:
    /// 绘制站场结点之间的连接
    void drawStationNodeLinks(maindrawscene *painter);
    /// 计算站场所有结点挂载点的角度
    void computerStationNodeMountAngles(void);
    /// 处理站场区段，得到区段占用情况
    void processStationSects(wxString sectName="");
    void processStationSect(wxString sectName="");
    /// 得到区段的颜色
    wxColour getSectColor(WBaseNode* startNode,WBaseNode* endNode);
    /// 得到区段的名称
    wxString getSectName(WBaseNode* startNode,WBaseNode* endNode);
    /// 搜索两个结点之间的进路
    std::list<tagSLRouteNode> searchRoute(WBaseNode* startNode,WBaseNode* endNode,
                                          MountDirection md);
    /// 转换输入信号为目标语句
    wxString Convertinputsignalintotargetstatement(std::string json_data);
    /// 转换输入信号为目标语句
    wxString Convertinputsignalintotargetstatement2(std::string json_data);
    /// 转换目标语句为输为信号
    wxString Converttargetstatementintooutputsignal(std::string opertype,std::string json_data);

private:
    wxRect mWorkingRect;                                           /**< 工作范围 */
    std::map<wxString,WBaseNode*> mNodes;                          /**< 管理所有的结点 */
    std::map<wxString,tagSectNode*> mSects;                        /**< 管理所有的区段 */
    std::map<wxString,tagSectNode> mdecSectNodes;                  /**< 当前站场使用的区段结点 */
    std::map<wxString,std::map<wxString,tagRoute*>> mRoutes;       /**< 保存当前选择的所有进路 */
    std::map<wxString,tagTimerItem> m_TimerItems;
    bool mLockedScreen;                                            /**< 锁定屏幕 */
    mutable std::mutex m_NodeMutex,m_SectMutex,m_DecSectMutex,m_RouteMutex,m_TimerMutex;       /**< 用于保护所有的结点 */
};

#endif // WNODEMANAGER_H
